// This is the main DLL file.

#include "stdafx.h"
#include <set>
#include <vcclr.h>
#include "avlib_wrapper.h"

#include <atlstr.h>
#include <stdio.h>
#include <string.h>
//#using <mscorlib.dll>


#if _MSC_VER > 1499 // Visual C++ 2008 only
#include <msclr/marshal.h>
using namespace msclr::interop;
#endif 
#include <msclr\marshal_cppstd.h>

using namespace System;
using namespace System::Runtime::InteropServices;
using System::IntPtr;
using System::Runtime::InteropServices::Marshal;
using System::Collections::ArrayList;
using System::Threading::Thread;
using System::Threading::ThreadStart;

#include "av_recorder\av_recorder.h"
using avlib::AVRecorder;

namespace avlib_wrapper {


	I_console_callback_t::I_console_callback_t(){
			pWrappedObject = new console_callback_proxy_t(this);
			if (!pWrappedObject)
				throw gcnew System::OutOfMemoryException("Allocation on C++ free store failed");
		};

	I_console_callback_t::~I_console_callback_t(){
			delete pWrappedObject;
			pWrappedObject = 0;
		}

ExecutorWrapper::ExecutorWrapper(){
	pExe = Executor::Instance();
}

ExecutorWrapper::~ExecutorWrapper(){
}

exec_id_t ExecutorWrapper::exec(System::String ^exe,System::String ^params,System::String ^workdir,I_console_callback_t ^parser,IntPtr data,bool support_cmd){
	char *str_exe = (char*)Marshal::StringToHGlobalAnsi(exe).ToPointer();
	char *str_param = (char*)Marshal::StringToHGlobalAnsi(params).ToPointer();
	char *str_workdir = (char*)Marshal::StringToHGlobalAnsi(workdir).ToPointer();
	return pExe->exec(str_exe,str_param,str_workdir,&(parser->GetWrappedObject()),data.ToPointer(),support_cmd);
}

bool ExecutorWrapper::command(exec_id_t id,System::String ^cmd){
	char *cmd_str = (char*)Marshal::StringToHGlobalAnsi(cmd).ToPointer();

	return Executor::command(id,cmd_str);
}

bool ExecutorWrapper::kill(exec_id_t id){
	return Executor::stop(id);
}

int ExecutorWrapper::pause(exec_id_t proc){
	return Executor::pause(proc);
}
int ExecutorWrapper::stop(exec_id_t proc){
	return Executor::stop(proc);
}
int ExecutorWrapper::resume(exec_id_t proc){
	return Executor::resume(proc);
}

//AVRecorderWrapper

AVRecorderWrapper::AVRecorderWrapper(){
	recorder = new AVRecorder();
	

}
AVRecorderWrapper::~AVRecorderWrapper(){
	if(recorder){

		delete recorder;
		recorder = NULL;
	}
}

void AVRecorderWrapper::Init(VideoDeviceCallbackManaged^vdev_cb,AudioDeviceCallbackmanaged^adev_cb){

	avlib::VideoDeviceCallback  vcb1 = NULL;
	avlib::AudioDeviceCallback  vcb2 = NULL;
	if(vdev_cb  &&  adev_cb){

		IntPtr cb1 = Marshal::GetFunctionPointerForDelegate(vdev_cb);
		IntPtr cb2 = Marshal::GetFunctionPointerForDelegate(adev_cb);
		

		vcb1 = static_cast<avlib::VideoDeviceCallback>(cb1.ToPointer());
		vcb2 = static_cast<avlib::AudioDeviceCallback>(cb2.ToPointer());
	}
	recorder->init(vcb1,vcb2);
}


void AVRecorderWrapper::set_record_callback(RecordProgressCallbackManaged^prog_cb,RecordErrorCallbackManaged^err_cb,RecordFinishedCallback ^end_cb){
	onProgress  = prog_cb;
	onError = err_cb;
	onFinished = end_cb;
	
	IntPtr cb3 = Marshal::GetFunctionPointerForDelegate(prog_cb);
	IntPtr cb4 = Marshal::GetFunctionPointerForDelegate(err_cb);

	avlib::RecordProgressCallback  vcb3 = static_cast<avlib::RecordProgressCallback>(cb3.ToPointer());
	avlib::RecordErrorCallback  vcb4 = static_cast<avlib::RecordErrorCallback>(cb4.ToPointer());

	recorder->set_record_callback(vcb3,vcb4);

}
void AVRecorderWrapper::set_fps(int fps){
	recorder->set_fps(fps);
}

bool AVRecorderWrapper::start(System::String ^avi_tmp,System::String ^thumb_tmp,IntPtr hwnd){
	msclr::interop::marshal_context context;
    std::string avi = context.marshal_as<std::string>(avi_tmp);
	std::string thumbnail = context.marshal_as<std::string>(thumb_tmp);

	return recorder->record(vid,aid,avi,thumbnail,(HWND)hwnd.ToInt32());
}

void AVRecorderWrapper::set_preview_window(System::IntPtr hwnd){
	recorder->window_resized((HWND)hwnd.ToInt32());
}

bool AVRecorderWrapper::stop(){
	if(recorder->is_recording()){
		Thread^ thread = gcnew Thread( gcnew ThreadStart(this,&AVRecorderWrapper::DoStop));
		thread->Start();
	}
	return true;
}

void AVRecorderWrapper::DoStop()
{
	recorder->stop();
	if(onFinished != nullptr) onFinished();
}

void AVRecorderWrapper::set_rect(int left,int top,int width,int height){
	recorder->set_rect(left,top,width,height);
}

double AVRecorderWrapper::get_duration(){
	return recorder->get_duration();
}

bool AVRecorderWrapper::is_recording(){
	return recorder->is_recording();
}

bool AVRecorderWrapper::query_dimension(int vid,ArrayList^ arr_dim){

	std::set<unsigned long> setDim;

	bool res = recorder->query_dimension(vid,setDim);
	if(res){

		std::set<unsigned long>::iterator it = setDim.begin();
		while(it != setDim.end()){
			arr_dim->Add(*it);
			it++;
		}
	}

	return res;
}

}